package com.jinyi.wwdeng.autodialer.utils

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.os.Environment
import android.util.Log
import androidx.core.app.ActivityCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

/**
 * 录音工具类
 */
object CallRecorderUtil {

    private const val TAG = "CallRecorder"

    private var audioRecord: AudioRecord? = null
    private var recordJob: Job? = null
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

    @Volatile
    private var isRecording = false

    private const val SAMPLE_RATE = 16000
    private const val CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO
    private const val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT

    private lateinit var recordDirPath: String

    private var pcmFile: File? = null
    private var wavFile: File? = null

    /** 初始化录音目录 */
    fun init() {
        try {
            val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
            val recordDir = File(downloadDir, "Recordings/${getCurrentDateFormatted()}")
            if (!recordDir.exists()) recordDir.mkdirs()
            recordDirPath = recordDir.absolutePath
        } catch (e: Exception) {
            Log.e(TAG, "init error: ${e.localizedMessage}", e)
        }
    }

    private fun getCurrentDateFormatted(): String {
        val formatter = SimpleDateFormat("yyyyMMdd", Locale.getDefault())
        return formatter.format(Date())
    }

    private fun generateFileName(number: String): String {
        val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
        val timestamp = sdf.format(Date())
        return "record_${number}_$timestamp"
    }

    /** 开始录音（传入通话号码，不带扩展名） */
    @Synchronized
    fun startRecording(context: Context, number: String): Boolean {
        if (isRecording) {
            Log.w(TAG, "Already recording")
            return false
        }

        if (!::recordDirPath.isInitialized) {
            init()
        }
        //目录被手动删除，需要重新创建
        val recordDir = File(recordDirPath)
        if (!recordDir.exists()){
            init()
        }

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "RECORD_AUDIO permission not granted")
            return false
        }

        return try {
            pcmFile = File(recordDirPath, "${generateFileName(number)}.pcm")
            wavFile = File(recordDirPath, "${generateFileName(number)}.wav")

            val minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT)
            if (minBufferSize == AudioRecord.ERROR || minBufferSize == AudioRecord.ERROR_BAD_VALUE) {
                Log.e(TAG, "Invalid buffer size")
                return false
            }

            audioRecord = AudioRecord(
                MediaRecorder.AudioSource.VOICE_CALL,
                SAMPLE_RATE,
                CHANNEL_CONFIG,
                AUDIO_FORMAT,
                minBufferSize
            )

            audioRecord?.startRecording()
            isRecording = true

            // 启动协程录音
            recordJob = scope.launch {
                writeAudioDataToFile(minBufferSize)
            }

            Log.d(TAG, "Recording started: $number")
            true
        } catch (e: Exception) {
            Log.e(TAG, "startRecording error: ${e.localizedMessage}", e)
            release()
            false
        }
    }

    /** 停止录音并返回 wav 文件路径 */
    suspend fun stopRecording(): String? {
        if (!isRecording) {
            Log.w(TAG, "stopRecording called but not recording")
            return null
        }

        isRecording = false

        return try {
            audioRecord?.stop()
            // 等待协程完成
            recordJob?.join()

            // PCM -> WAV
            withContext(Dispatchers.IO) {
                pcmToWav()
                //PCM 转 WAV完成删除pcm文件
                pcmFile?.delete()
            }
            wavFile?.absolutePath
        } catch (e: Exception) {
            Log.e(TAG, "stopRecording error: ${e.localizedMessage}", e)
            null
        } finally {
            release()
        }
    }

    fun stopRecording(callback: (String?) -> Unit) {
        scope.launch {
            val wavPath = stopRecording()
            withContext(Dispatchers.Main) {
                callback(wavPath)
            }
        }
    }

    /** 释放资源 */
    @Synchronized
    fun release() {
        try {
            audioRecord?.release()
        } catch (e: Exception) {
            Log.e(TAG, "release error: ${e.localizedMessage}", e)
        } finally {
            audioRecord = null
            recordJob = null
            isRecording = false
        }
    }

    /** 循环写 PCM 数据 */
    private fun writeAudioDataToFile(bufferSize: Int) {
        val buffer = ByteArray(bufferSize)
        try {
            FileOutputStream(pcmFile).use { fos ->
                while (isRecording && isActive()) {
                    val read = audioRecord?.read(buffer, 0, buffer.size) ?: 0
                    if (read > 0) fos.write(buffer, 0, read)
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "writeAudioDataToFile error: ${e.localizedMessage}", e)
        }
    }

    /** PCM 转 WAV */
    private fun pcmToWav() {
        val pcmSize = pcmFile?.length()?.toInt() ?: return
        val channels = 1
        val byteRate = SAMPLE_RATE * channels * 16 / 8

        val header = ByteArray(44)
        header[0] = 'R'.code.toByte(); header[1] = 'I'.code.toByte()
        header[2] = 'F'.code.toByte(); header[3] = 'F'.code.toByte()
        val totalLen = pcmSize + 36
        for (i in 0..3) header[4 + i] = ((totalLen shr (8 * i)) and 0xFF).toByte()
        header[8] = 'W'.code.toByte(); header[9] = 'A'.code.toByte()
        header[10] = 'V'.code.toByte(); header[11] = 'E'.code.toByte()

        // fmt chunk
        header[12] = 'f'.code.toByte(); header[13] = 'm'.code.toByte()
        header[14] = 't'.code.toByte(); header[15] = ' '.code.toByte()
        header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0
        header[20] = 1; header[21] = 0
        header[22] = channels.toByte(); header[23] = 0
        header[24] = (SAMPLE_RATE and 0xFF).toByte()
        header[25] = ((SAMPLE_RATE shr 8) and 0xFF).toByte()
        header[26] = ((SAMPLE_RATE shr 16) and 0xFF).toByte()
        header[27] = ((SAMPLE_RATE shr 24) and 0xFF).toByte()
        for (i in 0..3) header[28 + i] = ((byteRate shr (8 * i)) and 0xFF).toByte()
        val blockAlign = (channels * 16 / 8).toShort()
        header[32] = (blockAlign.toInt() and 0xFF).toByte()
        header[33] = ((blockAlign.toInt() shr 8) and 0xFF).toByte()
        header[34] = 16; header[35] = 0

        // data chunk
        header[36] = 'd'.code.toByte(); header[37] = 'a'.code.toByte()
        header[38] = 't'.code.toByte(); header[39] = 'a'.code.toByte()
        for (i in 0..3) header[40 + i] = ((pcmSize shr (8 * i)) and 0xFF).toByte()

        try {
            FileInputStream(pcmFile).use { input ->
                FileOutputStream(wavFile).use { output ->
                    output.write(header)
                    input.copyTo(output)
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "pcmToWav error: ${e.localizedMessage}", e)
        }
    }

    /** 检查协程是否活跃 */
    private fun isActive(): Boolean = recordJob?.isActive == true
}
